from django.shortcuts import render
from rest_framework import status
from rest_framework.response import Response
import base64
import pickle

from goods.models import SKU
from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer
from rest_framework.generics import GenericAPIView
from django_redis import get_redis_connection
from . import constants

# Create your views here.

class CartView(GenericAPIView):
    '''购物车'''
    serializer_class = CartSerializer

    def perform_authentication(self, request):
        '''重写父类的用户验证方法，不在进入视图前就检查JWT'''
        pass

    def post(self, request):
        '''保存购物车'''
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 判断用户是否登陆
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 用户以登录,保存到redis
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hincrby('cart_%s' % user.id, sku_id, count)

            # 设置勾选状态
            if selected:
                pl.sadd('cart_selected_%s' % user.id, sku_id)

            pl.execute()

            return Response(serializer.data)

        else:
            # 用户未登录, 保存到cookie中
            cart_str = request.COOKIES.get('cart')


            if cart_str:
                cart_str = cart_str.encode()

                # 解析购物车数据
                cart_bytes = base64.b64decode(cart_str)
                cart_dict = pickle.loads(cart_bytes)

            else:
                cart_dict = {}

            if sku_id in cart_dict:
                # 原本购物车有该商品数据
                cart_dict[sku_id]['count'] = cart_dict[sku_id]['count'] + count
                cart_dict[sku_id]['selected'] = selected

            else:
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }

            cart_bytes = pickle.dumps(cart_dict)
            cart_cookie = base64.b64encode(cart_bytes).decode()

            response = Response(serializer.data)
            response.set_cookie('cart', cart_cookie, constants.CART_COOKIE_EXPIRES)

            return response

    def get(self, request):
        """查询购物车"""
        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user = None

        # 保存
        if user and user.is_authenticated:
            # 如果用户已登录，查询redis，获取购物车数据 sku_id  count selected
            redis_conn = get_redis_connection('cart')
            # 查询hash，获取sku_id count
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)
            # redis_cart = {
            #     商品sku_id  bytes字节类型:  商品数量  bytes字节类型
            #     商品sku_id  bytes字节类型:  商品数量  bytes字节类型
            # ...
            # }

            # 查询set，获取勾选状态
            redis_cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
            # redis_cart_selected = set(勾选的商品的sku_id bytes类型, .....)

            # 遍历 redis_cart 形成下面要用到的cart_dict
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in redis_cart_selected
                }
        else:
            # 如果用户未登录，查询cookie，获取购物车数据 sku_id  count selected
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                # 表示用户有cookie中的购物车数据, cookie_cart是字符串
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示用户之前没有操作过购物车，没有数据
                cart_dict = {}

        # cart_dict = {
        #     sku_id: {
        #         count: 10
        #         selected: True
        #     },
        #     sku_id: {
        #         count: 20
        #         selected: False
        #     }
        # }
        sku_id_list = cart_dict.keys()
        # 查询数据库，获取完整商品信息数据
        sku_obj_list = SKU.objects.filter(id__in=sku_id_list)

        # 遍历sku_obj_list ，向对象中补充count和selected属性
        for sku in sku_obj_list:
            sku.count = cart_dict[sku.id]['count']
            sku.selected = cart_dict[sku.id]['selected']

        # 序列化返回
        serializer = CartSKUSerializer(sku_obj_list, many=True)
        return Response(serializer.data)

    def put(self, request):
        '''修改购物车'''
        # 校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']
        count = serializer.validated_data['count']
        selected = serializer.validated_data['selected']

        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user = None

        if user and user.is_authenticated:
            # 如果已登录 修改redis
            redis_conn = get_redis_connection('cart')

            pl = redis_conn.pipeline()
            # 修改数量 hash
            pl.hset('cart_%s' % user.id, sku_id, count)

            # 修改勾选状态 set
            if selected:
                # 增加勾选
                pl.sadd('cart_selected_%s' % user.id, sku_id)
            else:
                # 移除勾选
                pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()

            return Response(serializer.data)
        else:
            # 如果未登录 修改cookie
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                # cookie中有购物车数据 cookie_cart是字符串
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cart_dict = {}

            if sku_id in cart_dict:
                cart_dict[sku_id] = {
                    'count': count,
                    'selected': selected
                }

            cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response = Response(serializer.data)
            response.set_cookie('cart', cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        '''删除购物车'''
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        sku_id = serializer.validated_data['sku_id']

        # 判断用户是否登录
        try:
            user = request.user
        except Exception:
            user= None

        if user and user.is_authenticated:
            # 已登录,操作redis
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 删除hash数据
            pl.hdel('cart_%s' %user.id, sku_id)

            # 删除set数据
            pl.srem('cart_selected_%s' % user.id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)

        else:
            # 未登录 操作cookie
            cookie_cart = request.COOKIES.get('cart')

            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                cart_dict = {}

            response = Response(status=status.HTTP_204_NO_CONTENT)

            if sku_id in cart_dict:
                del cart_dict[sku_id]
                cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
                response.set_cookie('cart', cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)

            return response

class CartSelectAllView(GenericAPIView):
    '''购物车全选'''
    serializer_class = CartSelectAllSerializer

    def perform_authentication(self, request):
        pass

    def put(self, request):
        # 校验
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        selected = serializer.validated_data['selected']

        # 判断用户的登录状态
        # 判断用户的登录状态
        try:
            user = request.user
        except Exception:
            user = None

        # 修改
        if user and user.is_authenticated:
            # 已登录 操作redis
            redis_conn = get_redis_connection('cart')
            redis_cart = redis_conn.hgetall('cart_%s' % user.id)

            sku_id_list = redis_cart.keys()
            if selected:
                # 全选 添加所有sku_id 到redis_cart
                redis_conn.sadd('cart_selected_%s' % user.id, *sku_id_list)

            else:
                # 取消全选 清空redis_cart中的sku_id
                redis_conn.srem('cart_selected_%s' % user.id, *sku_id_list)

            return Response({'message': 'ok'})

        else:
            # 未登录 操作cookie
            # 未登录，操作cookie
            cookie_cart = request.COOKIES.get('cart')
            if cookie_cart:
                # 表示用户有cookie中的购物车数据, cookie_cart是字符串
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))
            else:
                # 表示用户之前没有操作过购物车，没有数据
                cart_dict = {}

            response = Response({"message": 'ok'})

            if cart_dict:
                for count_selected_dict in cart_dict.values():
                    count_selected_dict['selected'] = selected

                cart_cookie = base64.b64encode(pickle.dumps(cart_dict)).decode()
                response.set_cookie('cart', cart_cookie, max_age=constants.CART_COOKIE_EXPIRES)

            return response


